﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using CPDPWEM.Utils;

namespace UtilsUT
{
    [TestClass]
    public class BaseManageCommandsTests
    {
        [TestMethod]
        public void BasicFunctionality()
        {
            RandomViewModel rvm = new RandomViewModel();

            bool canExecuteCalled = false;
            bool isEnabled = false;
            rvm.MyCommandCanExecuteCalled += (sender, args) => canExecuteCalled = true;

            bool executeCalled = false;
            rvm.MyCommandExecuteCalled += (sender, args) => executeCalled = true;

            isEnabled = rvm.CanExecuteCommand("MyCommand");
            Assert.IsTrue(isEnabled);
            Assert.IsTrue(canExecuteCalled, "CanExecute for MyCommand appears to never have been called.");

            rvm.ExecuteCommand("MyCommand");
            Assert.IsTrue(executeCalled, "Execute for MyCommand appears to never have been called.");
        }

        [TestMethod]
        public void DefineExecuteButNoCanExecute()
        {
            RandomViewModel rvm = new RandomViewModel();

            // Verify: If an execute method is defined for a command but no can-execute, the command always appears
            // enabled.
            bool isCommandEnabled = rvm.CanExecuteCommand("OtherCommand");
            Assert.IsTrue(isCommandEnabled, "OtherCommand is not enabled, but should be");

            bool executeCalled = false;
            rvm.OtherCommandExecuteCalled += (sender, args) => executeCalled = true;
            rvm.ExecuteCommand("OtherCommand");
            Assert.IsTrue(executeCalled, "Execute for OtherCommand appears to never have been called.");
        }

        [TestMethod]
        public void ThrowsExceptionForUnknownCommandNames()
        {
            RandomViewModel rvm = new RandomViewModel();

            AssertThrows(() => rvm.CanExecuteCommand("UndefinedCommand"));
            AssertThrows(() => rvm.ExecuteCommand("UndefinedCommand"));
        }

        protected void AssertThrows(Action action)
        {
            bool exceptionThrown = false;
            try
            {
                action();
            }
            catch (Exception)
            {
                exceptionThrown = true;
            }
            finally
            {
                Assert.IsTrue(exceptionThrown, "Exception was expected to be thrown but was not.");
            }
        }
    }

    public class RandomViewModel : BaseManageCommands
    {
        public event EventHandler<EventArgs> MyCommandExecuteCalled;
        public event EventHandler<EventArgs> MyCommandCanExecuteCalled;

        public event EventHandler<EventArgs> OtherCommandExecuteCalled;

        [CommandExecute("MyCommand")]
        void MyCommand_Execute()
        {
            if (null != MyCommandExecuteCalled)
                MyCommandExecuteCalled(this, EventArgs.Empty);
        }

        [CommandCanExecute("MyCommand")]
        bool MyCommand_CanExecute()
        {
            if (null != MyCommandCanExecuteCalled)
                MyCommandCanExecuteCalled(this, EventArgs.Empty);
            return true;
        }

        [CommandExecute("OtherCommand")]
        void OtherCommand_Execute()
        {
            if (null != OtherCommandExecuteCalled)
                OtherCommandExecuteCalled(this, EventArgs.Empty);
        }

        /// <summary>
        /// Other, random function. Does nothing. Just adding something else to see how reflection handles this.
        /// </summary>
        void MyOtherFunction()
        { }
    }
}
